﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using BathhouseService.Areas.WX.Models.AccountVMs;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using WalkingTec.Mvvm.Core;
using WalkingTec.Mvvm.Core.Auth.Attribute;
using WalkingTec.Mvvm.Core.Extensions;
using WalkingTec.Mvvm.Mvc;

namespace BathhouseService.Areas.WX.Controllers
{
    [Area("WX")]
    [ActionDescription("手机端个人账号管")]
    public class AccountController : BaseController
    {

        #region 登录
        [Public]
        [ActionDescription("登录")]
        public IActionResult Login()
        {
            return View();
        }
        [Public]
        [HttpPost]
        public async Task<IActionResult> Login(string username, string pwd)
        {
            if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(pwd))
            {
                return Content("用户或密码不能为空");
            }
            var user = DC.Set<FrameworkUserBase>()
               .Include(x => x.UserRoles).Include(x => x.UserGroups)
               .Where(x => x.ITCode.ToLower() == username.ToLower() && x.Password == Utils.GetMD5String(pwd) && x.IsValid)
               .SingleOrDefault();
            if (user == null)
            {
                return Content("登录失败");
            }
            var roleIDs = user.UserRoles.Select(x => x.RoleId).ToList();
            var groupIDs = user.UserGroups.Select(x => x.GroupId).ToList();
            //查找登录用户的数据权限
            var dpris = DC.Set<DataPrivilege>()
                .Where(x => x.UserId == user.ID || (x.GroupId != null && groupIDs.Contains(x.GroupId.Value)))
                .Distinct()
                .ToList();
            ProcessTreeDp(dpris);
            //生成并返回登录用户信息
            LoginUserInfo rv = new LoginUserInfo
            {
                Id = user.ID,
                ITCode = user.ITCode,
                Name = user.Name,
                PhotoId = user.PhotoId,
                Roles = DC.Set<FrameworkRole>().Where(x => user.UserRoles.Select(y => y.RoleId).Contains(x.ID)).ToList(),
                Groups = DC.Set<FrameworkGroup>().Where(x => user.UserGroups.Select(y => y.GroupId).Contains(x.ID)).ToList(),
                DataPrivileges = dpris
            };
            LoginUserInfo = rv;
            AuthenticationProperties properties = null;
            properties = new AuthenticationProperties
            {
                IsPersistent = true,
                ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromDays(30))
            };
            var principal = LoginUserInfo.CreatePrincipal();
            // 在上面注册AddAuthentication时，指定了默认的Scheme，在这里便可以不再指定Scheme。
            await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal, properties);
            return Content("ok");

        }
        #endregion

        #region 注册
        [Public]
        [ActionDescription("注册")]
        public IActionResult Registered()
        {
            return View();
        }
        [Public]
        [HttpPost]
        public async Task<IActionResult> Registered(string username, string pwd, string pwdc, string name)
        {
            if (string.IsNullOrWhiteSpace(username) || string.IsNullOrWhiteSpace(pwd) || string.IsNullOrWhiteSpace(name) || string.IsNullOrWhiteSpace(pwdc))
            {
                return Content("用户名、姓名、密码不能为空");
            }
            if (pwd != pwdc)
            {
                return Content("密码或确认密码不能为空");
            }
            var chk = DC.Set<FrameworkUserBase>().Where(x => x.ITCode == username);
            if (chk.Count()>0)
            {
                return Content("该用户已注册");
            }
            FrameworkUserBase user = new FrameworkUserBase
            {
                ITCode = username,
                Password = Utils.GetMD5String(pwd),
                Name = name,
                IsValid = true
            };
            DC.Set<FrameworkUserBase>().Add(user);
            int q = await DC.SaveChangesAsync();
            if (q > 0)
            {
                return Content("ok");
            }
            return Content("系统错误");
        }
        #endregion


        #region 修改密码，修改资料
        [AllRights]
        [ActionDescription("修改个人信息")]
        public async Task<IActionResult> ModifyInformation(Guid userid)
        {
            var user = await DC.Set<FrameworkUserBase>().SingleOrDefaultAsync(x => x.ID == userid);
            RegisteredVM vm = CreateVM<RegisteredVM>();
            vm.Id = user.ID;
            vm.ITCode = user.ITCode;
            vm.Name = user.Name;          
            vm.ImgId = user.PhotoId;
            return View(vm);
        }
        [AllRights]
        [HttpPost]
        public async Task<IActionResult> ModifyInformation(RegisteredVM vm)
        {
            if (ModelState.IsValid)
            {
                var user = await DC.Set<FrameworkUserBase>().SingleOrDefaultAsync(x => x.ID == vm.Id);
                if (user == null)
                {
                    ModelState.AddModelError("", "系统错误,请重新登录");
                    return View(vm);
                }
                user.ITCode = vm.ITCode;
                user.Name = vm.Name;              
                user.IsValid = true;              
                user.PhotoId = vm.ImgId;
                DC.Set<FrameworkUserBase>().Update(user);
                int x = await DC.SaveChangesAsync();
                if (x > 0)
                {
                    return Redirect("/WX/Home/PersonalPage");
                }
                ModelState.AddModelError("", "系统错误");
                return View(vm);
            }
            return View(vm);
        }

        [Public]
        [ActionDescription("修改密码")]
        public async Task<IActionResult> Restpwd()
        {
            ViewBag.userinfo = await DC.Set<FrameworkUserBase>().SingleOrDefaultAsync(x => x.ID == LoginUserInfo.Id);
            return View();
        }
        #endregion


        #region 登出
        [AllRights]
        [ActionDescription("登出")]
        public async Task Logout()
        {
            HttpContext.Session.Clear();
            await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            HttpContext.Response.Redirect("/WX/Account/Login");
        }
        #endregion


        #region 找回密码
        [Public]
        [ActionDescription("忘记密码")]
        public IActionResult ForgotPassword()
        {
            return View();
        }
        [Public]
        [HttpPost]
        public async Task<IActionResult> ForgotPassword(string username, string name)
        {
            if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(name))
            {
                return Content("账户或密码不能为空");
            }
            var user = await DC.Set<FrameworkUserBase>().FirstOrDefaultAsync(x => x.ITCode == username && x.Name == name);
            if (user == null)
            {
                return Content("信息匹配");
            }
            return Content("ok");
        }
        [Public]
        [ActionDescription("重置密码")]
        public IActionResult ChangePassword()
        {
            return View();
        }
        [Public]
        [HttpPost]
        public async Task<IActionResult> ChangePassword(string pwd, string pwdc, string username)
        {
            if (string.IsNullOrEmpty(pwd) || string.IsNullOrEmpty(pwdc))
            {
                return Content("密码或确认密码不能为空");
            }
            if (pwd != pwdc)
            {
                return Content("密码和确认密码不一致");
            }
            var user = await DC.Set<FrameworkUserBase>().FirstOrDefaultAsync(x => x.ITCode == username);
            if (user == null)
            {
                return Content("信息错误！");
            }
            user.Password = Utils.GetMD5String(pwd);
            DC.Set<FrameworkUserBase>().Update(user);
            int x = await DC.SaveChangesAsync();
            if (x > 0)
            {
                return Content("ok");
            }
            else
            {
                return Content("系统错误");
            }
        }
        #endregion

        #region 公共方法
        private void ProcessTreeDp(List<DataPrivilege> dps)
        {
            var dpsSetting = GlobalServices.GetService<Configs>().DataPrivilegeSettings;
            foreach (var ds in dpsSetting)
            {
                if (typeof(ITreeData).IsAssignableFrom(ds.ModelType))
                {
                    var ids = dps.Where(x => x.TableName == ds.ModelName).Select(x => x.RelateId).ToList();
                    if (ids.Count > 0 && ids.Contains(null) == false)
                    {
                        List<Guid> tempids = new List<Guid>();
                        foreach (var item in ids)
                        {
                            if (Guid.TryParse(item, out Guid g))
                            {
                                tempids.Add(g);
                            }
                        }
                        List<Guid> subids = new List<Guid>();
                        subids.AddRange(GetSubIds(tempids.ToList(), ds.ModelType));
                        subids = subids.Distinct().ToList();
                        subids.ForEach(x => dps.Add(new DataPrivilege
                        {
                            TableName = ds.ModelName,
                            RelateId = x.ToString()
                        }));
                    }
                }
            }
        }

        private IEnumerable<Guid> GetSubIds(List<Guid> p_id, Type modelType)
        {
            var basequery = DC.GetType().GetTypeInfo().GetMethod("Set").MakeGenericMethod(modelType).Invoke(DC, null) as IQueryable;
            var subids = basequery.Cast<ITreeData>().Where(x => p_id.Contains(x.ParentId.Value)).Select(x => x.ID).ToList();
            if (subids.Count > 0)
            {
                return subids.Concat(GetSubIds(subids, modelType));
            }
            else
            {
                return new List<Guid>();
            }
        }
        #endregion


    }
}